import { isRoomInterval } from '@/ayaka'
import { enableRoom } from './strategy/enableRoom'
import { operateExtension } from './strategy/operateExtension'
import { operateFactory } from './strategy/operateFactory'
import { operateLab } from './strategy/operateLab'
import { operateStorage } from './strategy/operateStorage'
import { regenMineral } from './strategy/regenMineral'
import { regenSource } from './strategy/regenSource'
import { PCStrategyFn, PCTask, PCTaskType } from './types'
import { operatePower } from './strategy/operatePower'

/**
 * powerCreep 任务类型策略映射表
 */
const strategyMap: { [type in PCTaskType]?: PCStrategyFn } = {
    [PWR_OPERATE_STORAGE]: operateStorage,
    [PWR_OPERATE_LAB]: operateLab,
    [PWR_OPERATE_EXTENSION]: operateExtension,
    [PWR_REGEN_SOURCE]: regenSource,
    [PWR_REGEN_MINERAL]: regenMineral,
    [PWR_OPERATE_FACTORY]: operateFactory,
    [PWR_OPERATE_POWER]: operatePower,
}

const defaultStrategy: PCStrategyFn = (room, task) => PCTaskManager.deleteTaskByName(room, task.name)

/**
 * powerCreep 任务管理器
 */
export default class PCTaskManager {
    /**
     * 房间中 pc 指定技能的缓存
     */
    private static roomPcTypes: { [roomName: string]: Set<PCTaskType> } = {}

    /**
     * 运行
     */
    public static run(room: MyRoom) {
        const memory = PCTaskManager.getMemory(room)
        const tasks = (memory.tasks = memory.tasks.filter((task) => !task.done))
        const bindedPcNames = tasks.map((task) => task.pc).filter(Boolean) as string[]

        tasks.forEach((task) => {
            if (!task.pc && --task.timeout <= 0) {
                task.done = true
                return
            }

            PCTaskManager.bindPc(room, task, bindedPcNames)
            if (!task.pc) return

            if (!room.controller.isPowerEnabled) {
                enableRoom(room, task.pc)
                return
            }

            const strategy = strategyMap[task.type] || defaultStrategy
            strategy(room, task)
        })
    }

    /**
     * 获取 memory
     */
    public static getMemory(room: Room) {
        if (!room.memory.pc) {
            room.memory.pc = {
                tasks: [],
            }
        }
        return room.memory.pc
    }

    /**
     * 绑定 pc
     */
    public static bindPc(room: MyRoom, task: PCTask, pcNames: string[]) {
        if (task.pc) return

        const pcs = Object.values(Game.powerCreeps).filter(
            (pc) => pc.room?.name === room.name && !pcNames.includes(pc.name),
        )
        if (!pcs.length) return

        const pc = pcs
            .filter(
                (p) =>
                    p.powers[task.type] &&
                    p.ticksToLive! > 150 &&
                    !p.memory.renewing &&
                    (!p.powers[task.type].cooldown || p.powers[task.type].cooldown! < task.timeout),
            )
            .sort((p1, p2) => p2.powers[task.type].level - p1.powers[task.type].level)[0]
        if (!pc) return

        task.pc = pc.name
        pcNames.push(pc.name)
    }

    /**
     * 添加任务
     */
    public static addTask(room: MyRoom, name: string, type: PCTaskType, targetId: string, timeout = 20) {
        const { tasks } = PCTaskManager.getMemory(room)
        const task = {
            name,
            type,
            targetId,
            pc: '',
            timeout,
        }
        tasks.push(task)
    }

    /**
     * 删除任务
     */
    public static deleteTaskByName(room: MyRoom, name: string) {
        const { tasks } = PCTaskManager.getMemory(room)
        const index = tasks.findIndex((task) => task.name == name)
        if (index >= 0) {
            tasks.splice(index, 1)
        }
    }

    /**
     * 获取任务
     */
    public static getTaskByName(room: MyRoom, name: string) {
        const { tasks } = PCTaskManager.getMemory(room)
        return tasks.find((task) => task.name == name)
    }

    /**
     * 智能添加任务
     */
    public static autoAddTask(
        room: MyRoom,
        type: PCTaskType,
        target: RoomObject & _HasId,
        interval = 10,
        remainTick = 25,
        timeout = 20,
    ) {
        if (
            room.controller?.level === 8 &&
            PCTaskManager.hasPc(room as MyRoom, type) &&
            (!interval || isRoomInterval(room, interval)) &&
            (!target.effects?.length || target.effects[0].ticksRemaining < remainTick) &&
            !PCTaskManager.getTaskByName(room, `${type}-${target.id}`)
        ) {
            PCTaskManager.addTask(room, `${type}-${target.id}`, type, target.id, timeout)
            return true
        }
        return false
    }

    /**
     * 房间中是否有指定技能的 pc
     */
    public static hasPc(room: MyRoom, type: PCTaskType) {
        if (isRoomInterval(room, 311)) {
            delete PCTaskManager.roomPcTypes[room.name]
        }

        if (PCTaskManager.roomPcTypes[room.name]) {
            return PCTaskManager.roomPcTypes[room.name].has(type)
        }

        const types = new Set<PCTaskType>()
        const pcs = Object.values(Game.powerCreeps).filter((pc) => pc.room?.name === room.name)
        for (const pc of pcs) {
            for (const type in pc.powers) {
                types.add(Number(type) as PCTaskType)
            }
        }

        PCTaskManager.roomPcTypes[room.name] = types
        return types.has(type)
    }
}
